package com.lexicalscope.jewelcli.maven.report; /* * Copyright 2001-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static ch.lambdaj.Lambda.*; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.ResourceBundle; import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.doxia.sink.Sink; import org.apache.maven.doxia.siterenderer.Renderer; import org.apache.maven.project.MavenProject; import org.apache.maven.reporting.AbstractMavenReport; import org.apache.maven.reporting.MavenReportException; import ch.lambdaj.function.convert.Converter; import com.lexicalscope.jewel.cli.Cli; import com.lexicalscope.jewel.cli.CliFactory; import com.lexicalscope.jewel.cli.HelpMessage; import com.lexicalscope.jewel.cli.OptionHelpMessage; /** * Goal which produces a CLI help page for you maven site * * @author Tim Wood * @goal report * @execute phase="compile" lifecycle="jewelcli" * @requiresDependencyResolution compile * @requiresProject true * @requiresReports true */ public class JewelCliReportMojo extends AbstractMavenReport { private static final class AddDash implements Converter<String, String> { @Override public String convert(final String string) { return "-" + string; } } private static final class AddDashDash implements Converter<String, String> { @Override public String convert(final String string) { return "--" + string; } } /** * Directory where reports will go. * * @parameter expression="${project.reporting.outputDirectory}" * @required * @readonly */ private String outputDirectory; /** * @parameter default-value="${project}" * @required * @readonly */ private MavenProject project; /** * @component * @required * @readonly */ private Renderer siteRenderer; /** * The interfaces to output * * @parameter * @required */ private String[] interfaces; @Override public String getDescription(final Locale locale) { return getBundle(locale).getString("report.jewelcli.description"); } @Override public String getName(final Locale locale) { return getBundle(locale).getString("report.jewelcli.name"); } String[] getInterfaces() { return interfaces; } void setInterfaces(final String[] interfaces) { this.interfaces = interfaces; } @Override public String getOutputName() { return "command-line-interface"; } @Override protected void executeReport(final Locale locale) throws MavenReportException { final ClassLoader classLoader = getClassLoader(); final Class<?> interfaceClass = interfaceClass(classLoader); final Cli<?> cli = CliFactory.createCli(interfaceClass); getLog().debug("cli interface with " + cli); final Sink sink = getSink(); sink.head(); sink.title(); sink.text(getName(locale)); sink.title_(); sink.head_(); sink.body(); sink.section1(); sink.sectionTitle1(); sink.text(getBundle(locale).getString("report.jewelcli.title") + " " + getProject().getName()); sink.sectionTitle1_(); sink.lineBreak(); sink.text("Command line interface for " + " " + getProject().getName()); sink.lineBreak(); sink.lineBreak(); cli.describeTo(new HelpMessage() { @Override public void startOfOptions() { sink.table(); sink.tableRow(); sink.tableHeaderCell(); sink.text("Mandatory"); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text("Long Form"); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text("Short Form"); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text("Pattern"); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text("Description"); sink.tableHeaderCell_(); sink.tableRow_(); } @Override public OptionHelpMessage option() { return new OptionHelpMessage() { @Override public void startOptionalOption() { sink.tableRow(); sink.tableCell("true"); } @Override public void startMandatoryOption() { sink.tableRow(); sink.tableCell(); sink.text("true"); sink.tableCell_(); } @Override public void singleValuedWithCustomPattern(final String pattern) { sink.tableCell(); sink.text("/" + pattern + "/"); sink.tableCell_(); } @Override public void singleValued() { sink.tableCell(); sink.text("/.*/"); sink.tableCell_(); } @Override public void noValued() { sink.tableCell(); sink.tableCell_(); } @Override public void shortName(final List<String> shortNames) { sink.tableCell(); sink.text(join(convert(shortNames, new AddDash()), ", ")); sink.tableCell_(); } @Override public void multiValuedWithCustomPattern() { sink.tableCell(); sink.text("/.*/..."); sink.tableCell_(); } @Override public void multiValuedWithCustomPattern(final String pattern) { sink.tableCell(); sink.text("/" + pattern + "/..."); sink.tableCell_(); } @Override public void longName(final List<String> longNames) { sink.tableCell(); sink.text(join(convert(longNames, new AddDashDash()), ", ")); sink.tableCell_(); } @Override public void endOptionalOption(final String description) { sink.tableCell(); sink.text(description); sink.tableCell_(); sink.tableRow_(); } @Override public void endOptionalOption() { sink.tableCell(); sink.tableCell_(); sink.tableRow_(); } @Override public void endMandatoryOption(final String description) { sink.tableCell(); sink.text(description); sink.tableCell_(); sink.tableRow_(); } @Override public void endMandatoryOption() { sink.tableCell(); sink.tableCell_(); sink.tableRow_(); } }; } @Override public void noUsageInformation() { // nothing } @Override public void hasUsageInformation() { sink.text("Usage: "); } @Override public void hasUsageInformation(final String applicationName) { sink.text("Usage: " + applicationName + " "); } @Override public void hasUnparsedOption(final String valueName) { sink.text(valueName); } @Override public void hasUnparsedMultiValuedOption(final String valueName) { sink.text(valueName + "..."); } @Override public void hasSomeMandatoryOptions() { sink.text("options "); } @Override public void hasOnlyOptionalOptions() { sink.text("[options] "); } @Override public void endOfOptions() { sink.table_(); }; }); sink.lineBreak(); sink.section1_(); sink.body_(); sink.flush(); sink.close(); } private Class<?> interfaceClass(final ClassLoader classLoader) throws MavenReportException { final String interfac3 = interfaces[0]; getLog().debug("generating command line interface report for " + interfac3); try { return classLoader.loadClass(interfac3); } catch (final ClassNotFoundException e) { throw new MavenReportException("Unable to load interface class " + interfac3, e); } } @Override protected String getOutputDirectory() { return outputDirectory; } @Override protected MavenProject getProject() { return project; } @Override protected Renderer getSiteRenderer() { return siteRenderer; } private ResourceBundle getBundle(final Locale locale) { return ResourceBundle.getBundle("jewelcli-report", locale, this.getClass().getClassLoader()); } private ClassLoader getClassLoader() throws MavenReportException { final List<URL> urls = new ArrayList<URL>(); try { for (final Object object : project.getCompileClasspathElements()) { final String path = (String) object; final URL url = new File(path).toURL(); getLog().debug("adding classpath element " + url); urls.add(url); } } catch (final MalformedURLException e) { throw new MavenReportException("Unable to load command line interface class", e); } catch (final DependencyResolutionRequiredException e) { throw new MavenReportException("Unable to resolve dependencies of project", e); } return new URLClassLoader(urls.toArray(new URL[] {}), getClass().getClassLoader()); } }